#![allow(dead_code)]

struct RefLrn {}

impl RefLrn {
    pub fn hello() {
        println!("Ref learning!");
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn ref_deref_test() {
        // NOTE: i32 and &i32 is different type
        let mut x = 5;
        let y = &x;
        let z = &y;

        assert_eq!(x, *y);
        assert_eq!(x, **z);
        assert_eq!(&x, *z);

        generic_plus_one(&mut x);
        assert_eq!(6, x);

        fn generic_plus_one<T>(var: &mut T)
        where
            T: std::ops::Add<Output = T>
                + std::ops::AddAssign<T>
                + std::convert::From<i32>
                + std::cmp::PartialEq<i32>,
        {
            let one: T = 1.into();
            *var += one;
        }
    }

    #[test]
    #[allow(clippy::unnecessary_literal_unwrap)]
    #[allow(clippy::toplevel_ref_arg)]
    /// NOTE: 匹配模式用ref 借用
    /// 主要用在匹配模式中，ref var 和 &var 是等价的。
    /// 在非匹配模式中，ref var 会创建一个指向 var 的引用。
    fn classic_ref_test() {
        let maybe_name = Some(String::from("Alice"));

        // 匹配模式
        let _name = &maybe_name;
        let ref _ref_name = maybe_name;

        assert_eq!(_name, _ref_name);

        // 非匹配模式
        match maybe_name {
            Some(ref name) => println!("Hello, {}!", name),
            _ => println!("Hello, world!"),
        }

        println!("Hello again, {}", maybe_name.unwrap_or("world".into()));
    }

    #[test]
    #[allow(clippy::toplevel_ref_arg)]
    #[allow(unused_variables)]
    fn ref_convert() {
        // let ref a = var; SAME AS let a = &var;
        let var = 1;
        let ref a = var;
        let b = &var;

        let arr = vec![1, 2, 3];
        let ref x = arr;
        let y = &arr;

        let ref mut str = "hello".to_string();
        let ref ref_str = str;

        assert_eq!(a, b);
        assert_eq!(x, y);
        assert_eq!(str.as_ref(), *str);
    }
}
